home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / g__~1 / gplibs17.zoo / sbufvfor.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-02  |  20.1 KB  |  860 lines

  1. /*
  2.  * Copyright (c) 1990 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18.  
  19. #if defined(LIBC_SCCS) && !defined(lint)
  20. static char sccsid[] = "%W% (Berkeley) %G%";
  21. #endif /* LIBC_SCCS and not lint */
  22.  
  23. /*
  24.  * Actual printf innards.
  25.  *
  26.  * This code is large and complicated...
  27.  */
  28.  
  29. #include <sys/types.h>
  30. #include <ioprivat.h>
  31. #include <string.h>
  32. #include <stdarg.h>
  33.  
  34. /*
  35.  * Define FLOATING_POINT to get floating point.
  36.  */
  37. #ifndef    NO_FLOATING_POINT
  38. #define    FLOATING_POINT
  39. #endif
  40.  
  41. /* end of configuration stuff */
  42.  
  43.  
  44. /*
  45.  * Helper class and function for `fprintf to unbuffered': creates a
  46.  * temporary buffer.  We only work on write-only files; this avoids
  47.  * worries about ungetc buffers and so forth.
  48.  */
  49.  
  50. class help_streambuf : public backupbuf {
  51.   public:
  52.     char *buffer;
  53.     _G_size_t buf_size;
  54.     streambuf *sb;
  55.     help_streambuf(streambuf *sbuf, char *buf, _G_size_t n) {
  56.     sb = sbuf; buffer = buf; buf_size = n;
  57.     setp(buffer, buffer+buf_size); }
  58.     ~help_streambuf();
  59.     virtual int overflow(int c = EOF);
  60. };
  61.  
  62. int help_streambuf::overflow(int c)
  63. {
  64.     long used = pptr() - pbase();
  65.     if (used) {
  66.     sb->sputn(pbase(), used);
  67.     pbump(-used);
  68.     }
  69.     if (c == EOF || buf_size == 0)
  70.     return sb->overflow(c);
  71.     return sputc(c);
  72. }
  73. help_streambuf::~help_streambuf()
  74. {
  75.     long used = pptr() - pbase();
  76.     if (used) {
  77.     sb->sputn(pbase(), used);
  78.     pbump(-used);
  79.     }
  80. }
  81.  
  82. int help_vform(streambuf *sb, char const *fmt0, va_list ap)
  83. {
  84.     char buf[_G_BUFSIZ]; // WARNING: on the atari _G_BUFSIZ is a
  85.              // variable. thats OK with GCC but other
  86.              // compilers will barf!
  87.  
  88.     help_streambuf helper(sb, buf, _G_BUFSIZ);
  89.     return helper.vform(fmt0, ap);
  90. }
  91.  
  92. #ifdef FLOATING_POINT
  93.  
  94. #include <floatio.h>
  95. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  96. #define    DEFPREC        6
  97. extern "C" double modf(double, double*);
  98.  
  99. #else /* no FLOATING_POINT */
  100.  
  101. #define    BUF        40
  102.  
  103. #endif /* FLOATING_POINT */
  104.  
  105.  
  106. /*
  107.  * Macros for converting digits to letters and vice versa
  108.  */
  109. #define    to_digit(c)    ((c) - '0')
  110. #define is_digit(c)    ((unsigned)to_digit(c) <= 9)
  111. #define    to_char(n)    ((n) + '0')
  112.  
  113. /*
  114.  * Flags used during conversion.
  115.  */
  116. #define    LONGINT        0x01        /* long integer */
  117. #define    LONGDBL        0x02        /* long double; unimplemented */
  118. #define    SHORTINT    0x04        /* short integer */
  119. #define    ALT        0x08        /* alternate form */
  120. #define    LADJUST        0x10        /* left adjustment */
  121. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  122. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  123.  
  124. int streambuf::vform(char const *fmt0, _G_va_list ap)
  125. {
  126.     register const char *fmt; /* format string */
  127.     register int ch;    /* character from fmt */
  128.     register int n;        /* handy integer (short term usage) */
  129.     register char *cp;    /* handy char pointer (short term usage) */
  130.     const char *fmark;    /* for remembering a place in fmt */
  131.     register int flags;    /* flags as above */
  132.     int ret;        /* return value accumulator */
  133.     int width;        /* width from format (%8d), or 0 */
  134.     int prec;        /* precision from format (%.3d), or -1 */
  135.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  136. #ifdef FLOATING_POINT
  137.     int softsign;        /* temporary negative sign for floats */
  138.     double _double;        /* double precision arguments %[eEfgG] */
  139. #ifndef USE_DTOA
  140.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  141. #endif
  142. #endif
  143.     unsigned long _ulong;    /* integer arguments %[diouxX] */
  144.     enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
  145.     int dprec;        /* a copy of prec if [diouxX], 0 otherwise */
  146.     int dpad;        /* extra 0 padding needed for integers */
  147.     int fieldsz;        /* field size expanded by sign, dpad etc */
  148.     // The initialization of 'size' is to suppress a warning that
  149.     // 'size' might be used unitialized.  It seems gcc can't
  150.     // quite grok this spaghetti code ...
  151.     int size = 0;        /* size of converted field or string */
  152.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  153.     char ox[2];        /* space for 0x hex-prefix */
  154.  
  155.     /*
  156.      * Choose PADSIZE to trade efficiency vs size.  If larger
  157.      * printf fields occur frequently, increase PADSIZE (and make
  158.      * the initialisers below longer).
  159.      */
  160. #define    PADSIZE    16        /* pad chunk size */
  161.     static char const blanks[PADSIZE] =
  162.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  163.     static char const zeroes[PADSIZE] =
  164.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  165.  
  166.     /*
  167.      * BEWARE, these `goto error' on error, and PAD uses `n'.
  168.      */
  169. #define    PRINT(ptr, len) \
  170.   do { if (sputn(ptr, len) != len) goto error; } while (0)
  171. #if 1
  172. #define PAD_SP(howmany) if (padn(' ', howmany) < 0) goto error;
  173. #define PAD_0(howmany) if (padn('0', howmany) < 0) goto error;
  174. #else
  175. #define    PAD(howmany, with) { \
  176.     if ((n = (howmany)) > 0) { \
  177.         while (n > PADSIZE) { \
  178.             PRINT(with, PADSIZE); \
  179.             n -= PADSIZE; \
  180.         } \
  181.         PRINT(with, n); \
  182.     } \
  183. }
  184. #define PAD_SP(howmany) PAD(howmany, blanks)
  185. #define PAD_0(howmany) PAD(howmany, zeroes)
  186. #endif
  187.  
  188.     /*
  189.      * To extend shorts properly, we need both signed and unsigned
  190.      * argument extraction methods.
  191.      */
  192. #define    SARG() \
  193.     (flags&LONGINT ? va_arg(ap, long) : \
  194.         flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
  195.         (long)va_arg(ap, int))
  196. #define    UARG() \
  197.     (flags&LONGINT ? va_arg(ap, unsigned long) : \
  198.         flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
  199.         (unsigned long)va_arg(ap, unsigned int))
  200.  
  201.     /* optimise cerr (and other unbuffered Unix files) */
  202.     if (unbuffered())
  203.         return help_vform(this, fmt0, ap);
  204.  
  205.     fmt = fmt0;
  206.     ret = 0;
  207.  
  208.     /*
  209.      * Scan the format for conversions (`%' character).
  210.      */
  211.     for (;;) {
  212.         for (fmark = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
  213.             /* void */;
  214.         if ((n = fmt - fmark) != 0) {
  215.             PRINT(fmark, n);
  216.             ret += n;
  217.         }
  218.         if (ch == '\0')
  219.             goto done;
  220.         fmt++;        /* skip over '%' */
  221.  
  222.         flags = 0;
  223.         dprec = 0;
  224. #if defined(FLOATING_POINT) && !defined (USE_DTOA)
  225.         fpprec = 0;
  226. #endif
  227.         width = 0;
  228.         prec = -1;
  229.         sign = '\0';
  230.  
  231. rflag:        ch = *fmt++;
  232. reswitch:    switch (ch) {
  233.         case ' ':
  234.             /*
  235.              * ``If the space and + flags both appear, the space
  236.              * flag will be ignored.''
  237.              *    -- ANSI X3J11
  238.              */
  239.             if (!sign)
  240.                 sign = ' ';
  241.             goto rflag;
  242.         case '#':
  243.             flags |= ALT;
  244.             goto rflag;
  245.         case '*':
  246.             /*
  247.              * ``A negative field width argument is taken as a
  248.              * - flag followed by a positive field width.''
  249.              *    -- ANSI X3J11
  250.              * They don't exclude field widths read from args.
  251.              */
  252.             if ((width = va_arg(ap, int)) >= 0)
  253.                 goto rflag;
  254.             width = -width;
  255.             /* FALLTHROUGH */
  256.         case '-':
  257.             flags |= LADJUST;
  258.             flags &= ~ZEROPAD; /* '-' disables '0' */
  259.             goto rflag;
  260.         case '+':
  261.             sign = '+';
  262.             goto rflag;
  263.         case '.':
  264.             if ((ch = *fmt++) == '*') {
  265.                 n = va_arg(ap, int);
  266.                 prec = n < 0 ? -1 : n;
  267.                 goto rflag;
  268.             }
  269.             n = 0;
  270.             while (is_digit(ch)) {
  271.                 n = 10 * n + to_digit(ch);
  272.                 ch = *fmt++;
  273.             }
  274.             prec = n < 0 ? -1 : n;
  275.             goto reswitch;
  276.         case '0':
  277.             /*
  278.              * ``Note that 0 is taken as a flag, not as the
  279.              * beginning of a field width.''
  280.              *    -- ANSI X3J11
  281.              */
  282.             if (!(flags & LADJUST))
  283.                 flags |= ZEROPAD; /* '-' disables '0' */
  284.             goto rflag;
  285.         case '1': case '2': case '3': case '4':
  286.         case '5': case '6': case '7': case '8': case '9':
  287.             n = 0;
  288.             do {
  289.                 n = 10 * n + to_digit(ch);
  290.                 ch = *fmt++;
  291.             } while (is_digit(ch));
  292.             width = n;
  293.             goto reswitch;
  294. #ifdef FLOATING_POINT
  295.         case 'L':
  296.             flags |= LONGDBL;
  297.             goto rflag;
  298. #endif
  299.         case 'h':
  300.             flags |= SHORTINT;
  301.             goto rflag;
  302.         case 'l':
  303.             flags |= LONGINT;
  304.             goto rflag;
  305.         case 'c':
  306.             *(cp = buf) = va_arg(ap, int);
  307.             size = 1;
  308.             sign = '\0';
  309.             break;
  310.         case 'D':
  311.             flags |= LONGINT;
  312.             /*FALLTHROUGH*/
  313.         case 'd':
  314.         case 'i':
  315.             _ulong = SARG();
  316.             if ((long)_ulong < 0) {
  317.                 _ulong = -_ulong;
  318.                 sign = '-';
  319.             }
  320.             base = DEC;
  321.             goto number;
  322. #ifdef FLOATING_POINT
  323.         case 'e':
  324.         case 'E':
  325.         case 'f':
  326.         case 'F':
  327.         case 'g':
  328.         case 'G':
  329.             _double = va_arg(ap, double);
  330. #ifdef USE_DTOA
  331.             {
  332.                 ios::fmtflags fmt_flags = 0;
  333.                 int fill = ' ';
  334.                 if (flags & ALT)
  335.                 fmt_flags |= ios::showpoint;
  336.                 if (flags & LADJUST)
  337.                 fmt_flags |= ios::left;
  338.                 else if (flags & ZEROPAD)
  339.                 fmt_flags |= ios::internal, fill = '0';
  340.                 n = __outfloat(_double, this, ch, width,
  341.                        prec < 0 ? DEFPREC : prec,
  342.                        fmt_flags, sign, fill);
  343.                 if (n < 0)
  344.                 goto error;
  345.                 ret += n;
  346.             }
  347.             // CHECK ERROR!
  348.             continue;
  349. #else
  350.             /*
  351.              * don't do unrealistic precision; just pad it with
  352.              * zeroes later, so buffer size stays rational.
  353.              */
  354.             if (prec > MAXFRACT) {
  355.                 if ((ch != 'g' && ch != 'G') || (flags&ALT))
  356.                     fpprec = prec - MAXFRACT;
  357.                 prec = MAXFRACT;
  358.             } else if (prec == -1)
  359.                 prec = DEFPREC;
  360.             // __cvt_double may have to round up before the
  361.             // "start" of its buffer, i.e.
  362.             // ``intf("%.2f", (double)9.999);'';
  363.             // if the first character is still NUL, it did.
  364.             // softsign avoids negative 0 if _double < 0 but
  365.             // no significant digits will be shown.
  366.             cp = buf;
  367.             *cp = '\0';
  368.             size = __cvt_double(_double, prec, flags, &softsign,
  369.                         ch, cp, buf + sizeof(buf));
  370.             if (softsign)
  371.                 sign = '-';
  372.             if (*cp == '\0')
  373.                 cp++;
  374.             break;
  375. #endif
  376. #endif /* FLOATING_POINT */
  377.         case 'n':
  378.             if (flags & LONGINT)
  379.                 *va_arg(ap, long *) = ret;
  380.             else if (flags & SHORTINT)
  381.                 *va_arg(ap, short *) = ret;
  382.             else
  383.                 *va_arg(ap, int *) = ret;
  384.             continue;    /* no output */
  385.         case 'O':
  386.             flags |= LONGINT;
  387.             /*FALLTHROUGH*/
  388.         case 'o':
  389.             _ulong = UARG();
  390.             base = OCT;
  391.             goto nosign;
  392.         case 'p':
  393.             /*
  394.              * ``The argument shall be a pointer to void.  The
  395.              * value of the pointer is converted to a sequence
  396.              * of printable characters, in an implementation-
  397.              * defined manner.''
  398.              *    -- ANSI X3J11
  399.              */
  400.             /* NOSTRICT */
  401.             _ulong = (unsigned long)va_arg(ap, void *);
  402.             base = HEX;
  403.             flags |= HEXPREFIX;
  404.             ch = 'x';
  405.             goto nosign;
  406.         case 's':
  407.             if ((cp = va_arg(ap, char *)) == NULL)
  408.                 cp = "(null)";
  409.             if (prec >= 0) {
  410.                 /*
  411.                  * can't use strlen; can only look for the
  412.                  * NUL in the first `prec' characters, and
  413.                  * strlen() will go further.
  414.                  */
  415.                 char *p = (char*)memchr(cp, 0, prec);
  416.  
  417.                 if (p != NULL) {
  418.                     size = p - cp;
  419.                     if (size > prec)
  420.                         size = prec;
  421.                 } else
  422.                     size = prec;
  423.             } else
  424.                 size = strlen(cp);
  425.             sign = '\0';
  426.             break;
  427.         case 'U':
  428.             flags |= LONGINT;
  429.             /*FALLTHROUGH*/
  430.         case 'u':
  431.             _ulong = UARG();
  432.             base = DEC;
  433.             goto nosign;
  434.         case 'X':
  435.         case 'x':
  436.             _ulong = UARG();
  437.             base = HEX;
  438.             /* leading 0x/X only if non-zero */
  439.             if (flags & ALT && _ulong != 0)
  440.                 flags |= HEXPREFIX;
  441.  
  442.             /* unsigned conversions */
  443. nosign:            sign = '\0';
  444.             /*
  445.              * ``... diouXx conversions ... if a precision is
  446.              * specified, the 0 flag will be ignored.''
  447.              *    -- ANSI X3J11
  448.              */
  449. number:            if ((dprec = prec) >= 0)
  450.                 flags &= ~ZEROPAD;
  451.  
  452.             /*
  453.              * ``The result of converting a zero value with an
  454.              * explicit precision of zero is no characters.''
  455.              *    -- ANSI X3J11
  456.              */
  457.             cp = buf + BUF;
  458.             if (_ulong != 0 || prec != 0) {
  459.                     char *xdigs; /* digits for [xX] conversion */
  460.                 /*
  461.                  * unsigned mod is hard, and unsigned mod
  462.                  * by a constant is easier than that by
  463.                  * a variable; hence this switch.
  464.                  */
  465.                 switch (base) {
  466.                 case OCT:
  467.                     do {
  468.                         *--cp = to_char(_ulong & 7);
  469.                         _ulong >>= 3;
  470.                     } while (_ulong);
  471.                     /* handle octal leading 0 */
  472.                     if (flags & ALT && *cp != '0')
  473.                         *--cp = '0';
  474.                     break;
  475.  
  476.                 case DEC:
  477.                     /* many numbers are 1 digit */
  478.                     while (_ulong >= 10) {
  479.                         *--cp = to_char(_ulong % 10);
  480.                         _ulong /= 10;
  481.                     }
  482.                     *--cp = to_char(_ulong);
  483.                     break;
  484.  
  485.                 case HEX:
  486.                     if (ch == 'X')
  487.                         xdigs = "0123456789ABCDEF";
  488.                     else /* ch == 'x' || ch == 'p' */
  489.                         xdigs = "0123456789abcdef";
  490.                     do {
  491.                         *--cp = xdigs[_ulong & 15];
  492.                         _ulong >>= 4;
  493.                     } while (_ulong);
  494.                     break;
  495.  
  496.                 default:
  497.                     cp = "bug in vform: bad base";
  498.                     goto skipsize;
  499.                 }
  500.             }
  501.             size = buf + BUF - cp;
  502.         skipsize:
  503.             break;
  504.         default:    /* "%?" prints ?, unless ? is NUL */
  505.             if (ch == '\0')
  506.                 goto done;
  507.             /* pretend it was %c with argument ch */
  508.             cp = buf;
  509.             *cp = ch;
  510.             size = 1;
  511.             sign = '\0';
  512.             break;
  513.         }
  514.  
  515.         /*
  516.          * All reasonable formats wind up here.  At this point,
  517.          * `cp' points to a string which (if not flags&LADJUST)
  518.          * should be padded out to `width' places.  If
  519.          * flags&ZEROPAD, it should first be prefixed by any
  520.          * sign or other prefix; otherwise, it should be blank
  521.          * padded before the prefix is emitted.  After any
  522.          * left-hand padding and prefixing, emit zeroes
  523.          * required by a decimal [diouxX] precision, then print
  524.          * the string proper, then emit zeroes required by any
  525.          * leftover floating precision; finally, if LADJUST,
  526.          * pad with blanks.
  527.          */
  528.  
  529.         /*
  530.          * compute actual size, so we know how much to pad.
  531.          */
  532. #if defined(FLOATING_POINT) && !defined (USE_DTOA)
  533.         fieldsz = size + fpprec;
  534. #else
  535.         fieldsz = size;
  536. #endif
  537.         dpad = dprec - size;
  538.         if (dpad < 0)
  539.             dpad = 0;
  540.  
  541.         if (sign)
  542.             fieldsz++;
  543.         else if (flags & HEXPREFIX)
  544.             fieldsz += 2;
  545.         fieldsz += dpad;
  546.  
  547.         /* right-adjusting blank padding */
  548.         if ((flags & (LADJUST|ZEROPAD)) == 0)
  549.             PAD_SP(width - fieldsz);
  550.  
  551.         /* prefix */
  552.         if (sign) {
  553.             PRINT(&sign, 1);
  554.         } else if (flags & HEXPREFIX) {
  555.             ox[0] = '0';
  556.             ox[1] = ch;
  557.             PRINT(ox, 2);
  558.         }
  559.  
  560.         /* right-adjusting zero padding */
  561.         if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  562.             PAD_0(width - fieldsz);
  563.  
  564.         /* leading zeroes from decimal precision */
  565.         PAD_0(dpad);
  566.  
  567.         /* the string or number proper */
  568.         PRINT(cp, size);
  569.  
  570. #if defined(FLOATING_POINT) && !defined (USE_DTOA)
  571.         /* trailing f.p. zeroes */
  572.         PAD_0(fpprec);
  573. #endif
  574.  
  575.         /* left-adjusting padding (always blank) */
  576.         if (flags & LADJUST)
  577.             PAD_SP(width - fieldsz);
  578.  
  579.         /* finally, adjust ret */
  580.         ret += width > fieldsz ? width : fieldsz;
  581.  
  582.     }
  583. done:
  584.     return ret;
  585. error:
  586.     return EOF;
  587.     /* NOTREACHED */
  588. }
  589.  
  590. #if defined(FLOATING_POINT) && !defined(USE_DTOA)
  591.  
  592. static char *exponent(register char *p, register int exp, int fmtch)
  593. {
  594.     register char *t;
  595.     char expbuf[MAXEXP];
  596.  
  597.     *p++ = fmtch;
  598.     if (exp < 0) {
  599.         exp = -exp;
  600.         *p++ = '-';
  601.     }
  602.     else
  603.         *p++ = '+';
  604.     t = expbuf + MAXEXP;
  605.     if (exp > 9) {
  606.         do {
  607.             *--t = to_char(exp % 10);
  608.         } while ((exp /= 10) > 9);
  609.         *--t = to_char(exp);
  610.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  611.     }
  612.     else {
  613.         *p++ = '0';
  614.         *p++ = to_char(exp);
  615.     }
  616.     return (p);
  617. }
  618.  
  619. static char * round(double fract, int *exp,
  620.             register char *start, register char *end,
  621.             char ch, int *signp)
  622. {
  623.     double tmp;
  624.  
  625.     if (fract)
  626.     (void)modf(fract * 10, &tmp);
  627.     else
  628.         tmp = to_digit(ch);
  629.     if (tmp > 4)
  630.         for (;; --end) {
  631.             if (*end == '.')
  632.                 --end;
  633.             if (++*end <= '9')
  634.                 break;
  635.             *end = '0';
  636.             if (end == start) {
  637.                 if (exp) {    /* e/E; increment exponent */
  638.                     *end = '1';
  639.                     ++*exp;
  640.                 }
  641.                 else {        /* f; add extra digit */
  642.                 *--end = '1';
  643.                 --start;
  644.                 }
  645.                 break;
  646.             }
  647.         }
  648.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  649.     else if (*signp == '-')
  650.         for (;; --end) {
  651.             if (*end == '.')
  652.                 --end;
  653.             if (*end != '0')
  654.                 break;
  655.             if (end == start)
  656.                 *signp = 0;
  657.         }
  658.     return (start);
  659. }
  660.  
  661. int __cvt_double(double number, register int prec, int flags, int *signp,
  662.          int fmtch, char *startp, char *endp)
  663. {
  664.     register char *p, *t;
  665.     register double fract;
  666.     int dotrim = 0, expcnt, gformat = 0;
  667.     double integer, tmp;
  668.  
  669.     expcnt = 0;
  670.     if (number < 0) {
  671.         number = -number;
  672.         *signp = '-';
  673.     } else
  674.         *signp = 0;
  675.  
  676.     fract = modf(number, &integer);
  677.  
  678.     /* get an extra slot for rounding. */
  679.     t = ++startp;
  680.  
  681.     /*
  682.      * get integer portion of number; put into the end of the buffer; the
  683.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  684.      */
  685.     for (p = endp - 1; integer; ++expcnt) {
  686.         tmp = modf(integer / 10, &integer);
  687.         *p-- = to_char((int)((tmp + .01) * 10));
  688.     }
  689.     switch (fmtch) {
  690.     case 'f':
  691.     case 'F':
  692.         /* reverse integer into beginning of buffer */
  693.         if (expcnt)
  694.             for (; ++p < endp; *t++ = *p);
  695.         else
  696.             *t++ = '0';
  697.         /*
  698.          * if precision required or alternate flag set, add in a
  699.          * decimal point.
  700.          */
  701.         if (prec || flags&ALT)
  702.             *t++ = '.';
  703.         /* if requires more precision and some fraction left */
  704.         if (fract) {
  705.             if (prec)
  706.                 do {
  707.                     fract = modf(fract * 10, &tmp);
  708.                     *t++ = to_char((int)tmp);
  709.                 } while (--prec && fract);
  710.             if (fract)
  711.                 startp = round(fract, (int *)NULL, startp,
  712.                     t - 1, (char)0, signp);
  713.         }
  714.         for (; prec--; *t++ = '0');
  715.         break;
  716.     case 'e':
  717.     case 'E':
  718. eformat:    if (expcnt) {
  719.             *t++ = *++p;
  720.             if (prec || flags&ALT)
  721.                 *t++ = '.';
  722.             /* if requires more precision and some integer left */
  723.             for (; prec && ++p < endp; --prec)
  724.                 *t++ = *p;
  725.             /*
  726.              * if done precision and more of the integer component,
  727.              * round using it; adjust fract so we don't re-round
  728.              * later.
  729.              */
  730.             if (!prec && ++p < endp) {
  731.                 fract = 0;
  732.                 startp = round((double)0, &expcnt, startp,
  733.                     t - 1, *p, signp);
  734.             }
  735.             /* adjust expcnt for digit in front of decimal */
  736.             --expcnt;
  737.         }
  738.         /* until first fractional digit, decrement exponent */
  739.         else if (fract) {
  740.             /* adjust expcnt for digit in front of decimal */
  741.             for (expcnt = -1;; --expcnt) {
  742.                 fract = modf(fract * 10, &tmp);
  743.                 if (tmp)
  744.                     break;
  745.             }
  746.             *t++ = to_char((int)tmp);
  747.             if (prec || flags&ALT)
  748.                 *t++ = '.';
  749.         }
  750.         else {
  751.             *t++ = '0';
  752.             if (prec || flags&ALT)
  753.                 *t++ = '.';
  754.         }
  755.         /* if requires more precision and some fraction left */
  756.         if (fract) {
  757.             if (prec)
  758.                 do {
  759.                     fract = modf(fract * 10, &tmp);
  760.                     *t++ = to_char((int)tmp);
  761.                 } while (--prec && fract);
  762.             if (fract)
  763.                 startp = round(fract, &expcnt, startp,
  764.                     t - 1, (char)0, signp);
  765.         }
  766.         /* if requires more precision */
  767.         for (; prec--; *t++ = '0');
  768.  
  769.         /* unless alternate flag, trim any g/G format trailing 0's */
  770.         if (gformat && !(flags&ALT)) {
  771.             while (t > startp && *--t == '0');
  772.             if (*t == '.')
  773.                 --t;
  774.             ++t;
  775.         }
  776.         t = exponent(t, expcnt, fmtch);
  777.         break;
  778.     case 'g':
  779.     case 'G':
  780.         /* a precision of 0 is treated as a precision of 1. */
  781.         if (!prec)
  782.             ++prec;
  783.         /*
  784.          * ``The style used depends on the value converted; style e
  785.          * will be used only if the exponent resulting from the
  786.          * conversion is less than -4 or greater than the precision.''
  787.          *    -- ANSI X3J11
  788.          */
  789.         if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
  790.             /*
  791.              * g/G format counts "significant digits, not digits of
  792.              * precision; for the e/E format, this just causes an
  793.              * off-by-one problem, i.e. g/G considers the digit
  794.              * before the decimal point significant and e/E doesn't
  795.              * count it as precision.
  796.              */
  797.             --prec;
  798.             fmtch -= 2;        /* G->E, g->e */
  799.             gformat = 1;
  800.             goto eformat;
  801.         }
  802.         /*
  803.          * reverse integer into beginning of buffer,
  804.          * note, decrement precision
  805.          */
  806.         if (expcnt)
  807.             for (; ++p < endp; *t++ = *p, --prec);
  808.         else
  809.             *t++ = '0';
  810.         /*
  811.          * if precision required or alternate flag set, add in a
  812.          * decimal point.  If no digits yet, add in leading 0.
  813.          */
  814.         if (prec || flags&ALT) {
  815.             dotrim = 1;
  816.             *t++ = '.';
  817.         }
  818.         else
  819.             dotrim = 0;
  820.         /* if requires more precision and some fraction left */
  821.         if (fract) {
  822.             if (prec) {
  823.                 /* If no integer part, don't count initial
  824.                  * zeros as significant digits. */
  825.                 do {
  826.                     fract = modf(fract * 10, &tmp);
  827.                     *t++ = to_char((int)tmp);
  828.                 } while(!tmp && !expcnt);
  829.                 while (--prec && fract) {
  830.                     fract = modf(fract * 10, &tmp);
  831.                     *t++ = to_char((int)tmp);
  832.                 }
  833.             }
  834.             if (fract)
  835.                 startp = round(fract, (int *)NULL, startp,
  836.                     t - 1, (char)0, signp);
  837.         }
  838.         /* alternate format, adds 0's for precision, else trim 0's */
  839.         if (flags&ALT)
  840.             for (; prec--; *t++ = '0');
  841.         else if (dotrim) {
  842.             while (t > startp && *--t == '0');
  843.             if (*t != '.')
  844.                 ++t;
  845.         }
  846.     }
  847.     return (t - startp);
  848. }
  849.  
  850. #endif /* defined(FLOATING_POINT) && !defined(USE_DTOA) */
  851.  
  852. int streambuf::form(char const *format ...)
  853. {
  854.     va_list ap;
  855.     va_start(ap, format);
  856.     int count = vform(format, ap);
  857.     va_end(ap);
  858.     return count;
  859. }
  860.